package dse.messages.multiversion;

import java.util.LinkedList;

import dse.Cluster;
import dse.DataObject;
import dse.DataShare;
import dse.Experiment;
import dse.ExperimentRecorder;
import dse.Node;
import dse.Version;
import dse.messages.Message;
import dse.messages.MessageHandler;
import dse.messages.MessageSender;
import dse.messages.MessageType;
import dse.messages.singleversion.ShareDownloader;

public class ShareUpdateTLOMessageHandler extends MessageSender implements
		MessageHandler {

	private DataObject dobj;
	private Version version;
	//private Cluster home;
	private LinkedList<Cluster> ring;
	private boolean tranx;
	private boolean repair;
	private ShareDownloader downloader;
	
	public ShareUpdateTLOMessageHandler (Experiment experiment, DataObject dobj,
			Version version, boolean tranx, boolean repair, LinkedList<Cluster> ring, ShareDownloader downloader)
	{
		super(experiment);
		
		this.dobj = dobj;
		this.version = version;
		this.tranx = tranx;
		this.downloader = downloader;
		//this.home = home;
		if(ring != null){
			this.ring = new LinkedList<Cluster>();
			this.ring.addAll(ring);
		}
		else
			this.ring = null;
		this.repair = repair;
	}
	
	@Override
	public boolean acceptMessage(Message message) {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public void messageInterupted(ExperimentRecorder recorder, Message message,
			double time) {
		// TODO Auto-generated method stub
		recorder.debug(this, "msgIntrpt: " + message, time);
		if(tranx)
			downloader.shareUpdateFailed(recorder, dobj, 0, time);
		//Message m = super.createShareUpdateV4ResponseMessage(message.to(), message.from(), 
		//		dobj, shareIndex, tranx, false, message.purpose(), downloader);

		//recorder.debug(this, "new msg: " + m, time);
		//experiment.messageQueue().enqueueMessage(m, time);
	}

	@Override
	public void messageReceived(ExperimentRecorder recorder, Message message,
			double time) {
		// TODO Auto-generated method stub
		recorder.debug(this, "msgRcvd: " + message, time);
		if (message.messageType() != MessageType.ShareUpdateTLO) {
			recorder.warn(
					"ShareUpdateTLOMessageHandler recieved " + 
					message.messageType() + " message."
					);
			return;
		}			
		// What do we know about the share?
		Node receiver = message.to();
		
		// Does the receiver have the share?
		DataShare share = receiver.getDataShare(dobj);
		if (share != null)
		{
			// Then we need to send a new message BACK (thats why to and from
			// are reversed!
			boolean contain = share.addNewVersion(version);			
			if(tranx)
				downloader.shareUpdated(recorder, message.from(), dobj, share.getIndex(), time);
			
			if(contain){
				Node sn = experiment.network().lookupCluster(receiver.clusterId()).superNode();
				Message m = super.createUpdateSuccessTLOMessage(receiver, sn, dobj, version, message.purpose());
				recorder.debug(this, "new msg: " + m, time);
				experiment.messageQueue().enqueueMessage(m, time);
			}
			
			if(!repair && contain){				
				if(ring.size() == 0){
					downloader.shareDownloaded(recorder, message.to(), dobj, share.getIndex(), time);
					return;
				}
				Node to = experiment.modules().assigner().assign(dobj, share.getIndex(), ring.removeFirst());
				Message m = super.createShareUpdateTLOMessage(receiver, to, dobj, version, false, false, ring, message.purpose(), downloader);
				recorder.debug(this, "new msg: " + m, time);
				experiment.messageQueue().enqueueMessage(m, time);
			}
		}
		else
		{
			this.messageInterupted(recorder, message, time);
		}
	}
}
